package com.bean.util;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.Setting;
import com.bean.annotation.Id;
import com.bean.annotation.Table;
import com.bean.annotation.TableField;
import com.bean.entity.OfficialAccount;
import com.bean.entity.User;
import com.bean.exception.UnSupportException;
import com.bean.template.SqlTemplate;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class SqlUtil {
    private final static String beanType;
    private final static String beanField;
    private final static String beanScan;
    private final static String beanUnder;
    private final static String dbType;
    private final static String sqlPath;

    static {
        final Setting setting = new Setting("config.setting");
        beanType = setting.get("bean.type");
        beanField = setting.get("bean.field");
        beanScan = setting.get("bean.scan");
        beanUnder = setting.get("bean.under");
        dbType = setting.get("db.type");
        sqlPath = setting.get("sql.path");
    }

    public static String generateFieldSql(Field field) {
        StringBuilder fieldSql = new StringBuilder();
        TableField fieldAnnotation = field.getAnnotation(TableField.class);
        if ("on".equals(beanUnder)) {
            fieldSql.append(StrUtil.toUnderlineCase(field.getName()));
        } else {
            fieldSql.append(field.getName());
        }
        if ("Integer".equals(field.getType().getSimpleName())) {
            if (fieldAnnotation == null) {
                fieldSql.append(" int(11) ");
            } else {
                if (fieldAnnotation.length() != -1) {
                    fieldSql.append(" int(").append(fieldAnnotation.length()).append(") ");
                } else {
                    fieldSql.append(" int(11) ");
                }
                if (fieldAnnotation.notNull()) {
                    fieldSql.append(" not null ");
                }
                if (StrUtil.isNotBlank(fieldAnnotation.defaultValue())) {
                    fieldSql.append(" default ").append(fieldAnnotation.defaultValue());
                }
                if (StrUtil.isNotBlank(fieldAnnotation.comment())) {
                    fieldSql.append(" comment ").append("'").append(fieldAnnotation.comment()).append("'");
                }
            }
        } else if ("Long".equals(field.getType().getSimpleName())) {
            if (fieldAnnotation == null) {
                fieldSql.append(" bigint(20) ");
            } else {
                if (fieldAnnotation.length() != -1) {
                    fieldSql.append(" bigint(").append(fieldAnnotation.length()).append(") ");
                } else {
                    fieldSql.append(" bigint(20) ");
                }
                if (fieldAnnotation.notNull()) {
                    fieldSql.append(" not null ");
                }
                if (StrUtil.isNotBlank(fieldAnnotation.defaultValue())) {
                    fieldSql.append(" default ").append(fieldAnnotation.defaultValue());
                }
                if (StrUtil.isNotBlank(fieldAnnotation.comment())) {
                    fieldSql.append(" comment ").append("'").append(fieldAnnotation.comment()).append("'");
                }
            }
        } else if ("String".equals(field.getType().getSimpleName())) {
            if (fieldAnnotation == null) {
                fieldSql.append(" varchar(255) ");
            } else {
                if (fieldAnnotation.length() != -1) {
                    fieldSql.append(" varchar(").append(fieldAnnotation.length()).append(") ");
                } else {
                    fieldSql.append(" varchar(255) ");
                }
                if (fieldAnnotation.notNull()) {
                    fieldSql.append(" not null ");
                }
                if (StrUtil.isNotBlank(fieldAnnotation.defaultValue())) {
                    fieldSql.append(" default ").append("'").append(fieldAnnotation.defaultValue()).append("'");
                }
                if (StrUtil.isNotBlank(fieldAnnotation.comment())) {
                    fieldSql.append(" comment ").append("'").append(fieldAnnotation.comment()).append("'");
                }
            }
        } else if ("Date".equals(field.getType().getSimpleName())) {
            if (fieldAnnotation == null) {
                fieldSql.append(" datetime ");
            } else {
                if (fieldAnnotation.length() != -1) {
                    fieldSql.append(" datetime(").append(fieldAnnotation.length()).append(") ");
                } else {
                    fieldSql.append(" datetime ");

                }
                if (fieldAnnotation.notNull()) {
                    fieldSql.append(" not null ");
                }
                if (StrUtil.isNotBlank(fieldAnnotation.defaultValue())) {
                    fieldSql.append(" default ").append(fieldAnnotation.defaultValue());
                }
                if (StrUtil.isNotBlank(fieldAnnotation.comment())) {
                    fieldSql.append(" comment ").append("'").append(fieldAnnotation.comment()).append("'");
                }
            }
        } else if ("LocalDateTime".equals(field.getType().getSimpleName())) {
            if (fieldAnnotation == null) {
                fieldSql.append(" datetime ");
            } else {
                if (fieldAnnotation.length() != -1) {
                    fieldSql.append(" datetime(").append(fieldAnnotation.length()).append(") ");
                } else {
                    fieldSql.append(" datetime ");

                }
                if (fieldAnnotation.notNull()) {
                    fieldSql.append(" not null ");
                }
                if (StrUtil.isNotBlank(fieldAnnotation.defaultValue())) {
                    fieldSql.append(" default ").append(fieldAnnotation.defaultValue());
                }
                if (StrUtil.isNotBlank(fieldAnnotation.comment())) {
                    fieldSql.append(" comment ").append("'").append(fieldAnnotation.comment()).append("'");
                }
            }
        } else if ("LocalDate".equals(field.getType().getSimpleName())) {
            if (fieldAnnotation == null) {
                fieldSql.append(" date ");
            } else {
                if (fieldAnnotation.length() != -1) {
                    fieldSql.append(" date(").append(fieldAnnotation.length()).append(") ");
                } else {
                    fieldSql.append(" date ");

                }
                if (fieldAnnotation.notNull()) {
                    fieldSql.append(" not null ");
                }
                if (StrUtil.isNotBlank(fieldAnnotation.defaultValue())) {
                    fieldSql.append(" default ").append(fieldAnnotation.defaultValue());
                }
                if (StrUtil.isNotBlank(fieldAnnotation.comment())) {
                    fieldSql.append(" comment ").append("'").append(fieldAnnotation.comment()).append("'");
                }
            }
        }else if("Double".equals(field.getType().getSimpleName())){
            if (fieldAnnotation == null) {
                fieldSql.append(" double ");
            } else {
                if (fieldAnnotation.length() != -1) {
                    fieldSql.append(" double(").append(fieldAnnotation.length()).append(",0) ");
                } else {
                    fieldSql.append(" double ");

                }
                if (fieldAnnotation.notNull()) {
                    fieldSql.append(" not null ");
                }
                if (StrUtil.isNotBlank(fieldAnnotation.defaultValue())) {
                    fieldSql.append(" default ").append(fieldAnnotation.defaultValue());
                }
                if (StrUtil.isNotBlank(fieldAnnotation.comment())) {
                    fieldSql.append(" comment ").append("'").append(fieldAnnotation.comment()).append("'");
                }
            }
        }else if("Float".equals(field.getType().getSimpleName())){
            if (fieldAnnotation == null) {
                fieldSql.append(" float ");
            } else {
                if (fieldAnnotation.length() != -1) {
                    fieldSql.append(" float(").append(fieldAnnotation.length()).append(",0) ");
                } else {
                    fieldSql.append(" float ");

                }
                if (fieldAnnotation.notNull()) {
                    fieldSql.append(" not null ");
                }
                if (StrUtil.isNotBlank(fieldAnnotation.defaultValue())) {
                    fieldSql.append(" default ").append(fieldAnnotation.defaultValue());
                }
                if (StrUtil.isNotBlank(fieldAnnotation.comment())) {
                    fieldSql.append(" comment ").append("'").append(fieldAnnotation.comment()).append("'");
                }
            }
        }else if("BigDecimal".equals(field.getType().getSimpleName())){

            if (fieldAnnotation == null) {
                fieldSql.append(" double ");
            } else {
                if (fieldAnnotation.length() != -1) {
                    fieldSql.append(" double(").append(fieldAnnotation.length()).append(",0) ");
                } else {
                    fieldSql.append(" double");

                }
                if (fieldAnnotation.notNull()) {
                    fieldSql.append(" not null ");
                }
                if (StrUtil.isNotBlank(fieldAnnotation.defaultValue())) {
                    fieldSql.append(" default ").append(fieldAnnotation.defaultValue());
                }
                if (StrUtil.isNotBlank(fieldAnnotation.comment())) {
                    fieldSql.append(" comment ").append("'").append(fieldAnnotation.comment()).append("'");
                }
            }
        }
        Id id = field.getAnnotation(Id.class);
        if (id != null) {
            fieldSql.append(" primary key ");
            if ("auto".equals(beanType)) {
                if ("Integer".equals(field.getType().getSimpleName()) || "Long".equals(field.getType().getSimpleName())) {
                    fieldSql.append(" auto_increment ");
                }

            }
        }
        fieldSql.append(",\n");

        return fieldSql.toString();
    }

    public static String generateTableSql(Class<?> clazz) {
        StringBuilder sql = new StringBuilder();
        if ("mysql".equals(dbType)) {
            Table annotation = clazz.getAnnotation(Table.class);
            if (annotation == null || annotation.isGenerate()) {
                String tablePrefix = SqlTemplate.tablePrefix;
                if ("on".equals(beanUnder)) {
                    tablePrefix = tablePrefix.replaceAll("\\$\\{}", StrUtil.toUnderlineCase(clazz.getSimpleName()));
                } else {
                    tablePrefix = tablePrefix.replaceAll("\\$\\{}", StrUtil.lowerFirst(clazz.getSimpleName()));
                }
                StringBuilder builder = new StringBuilder();
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    if ("private".equals(beanField)) {
                        if (field.getModifiers() == Modifier.PRIVATE) {
                            builder.append(generateFieldSql(field));
                        }
                    } else {
                        builder.append(generateFieldSql(field));
                    }
                }
                sql.append(tablePrefix);
                sql.append(builder.substring(0, builder.length() - 2));
                if (annotation != null) {
                    if (StrUtil.isNotBlank(annotation.comment())) {
                        sql.append(SqlTemplate.tableSuffix.replaceAll("\\$\\{}", "comment='" + annotation.comment() + "'"));
                    } else {
                        sql.append(SqlTemplate.tableSuffix.replaceAll("\\$\\{}", ""));
                    }
                } else {
                    sql.append(SqlTemplate.tableSuffix.replaceAll("\\$\\{}", ""));
                }
            }
        } else {
            throw new UnSupportException();
        }
        return sql.toString();
    }

    public static void generateSqlFile() {
        String path = System.getProperty("user.dir");
        if (StrUtil.isNotBlank(sqlPath)) {
            path = sqlPath;
        }
        FileOutputStream outputStream = null;
        try {
            File file = new File(path + "/table.sql");
            if (!file.exists()) {
                file.createNewFile();
            }
            outputStream = new FileOutputStream(file);
            StringBuilder sql = new StringBuilder();
            Set<Class<?>> classSet = ClassUtil.scanPackage(beanScan);
            classSet.forEach(aClass -> {
                String tableSql = generateTableSql(aClass);
                sql.append(tableSql + "\n\n");
            });
            outputStream.write(sql.toString().getBytes());

        } catch (Exception e) {
            System.out.println(e.getMessage());
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (Exception ze) {

                }
            }
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (Exception ze) {

                }
            }
        }


    }

}
